package com.framework.security.util;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.*;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * @version V1.0
 * @program: teamwork
 * @package: com.framework.security.util
 * @description: redis操作工具类
 * @author: lzd
 * @create: 2020-06-25 10:42
 **/
@Component
@Slf4j
public class RedisCache {

    @Autowired
    public RedisTemplate redisTemplate;

    public static Map<String, Object> map = new ConcurrentHashMap<>();

    public static Map<String, Long> mapTsp = new ConcurrentHashMap<>();
    public static Map<String, Integer> mapTimeout = new ConcurrentHashMap<>();
    public static Map<String, TimeUnit> mapTimeUnit = new ConcurrentHashMap<>();

    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param key   缓存的键值
     * @param value 缓存的值
     * @return 缓存的对象
     */
    public <T> ValueOperations<String, T> setCacheObject(String key, T value) {
        if(map != null) {
            map.put(key, value);
            mapTsp.put(key, new Date().getTime());
            return null;
        }
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        operation.set(key, value);
        return operation;
    }

    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param timeout  时间
     * @param timeUnit 时间颗粒度
     * @return 缓存的对象
     */
    public <T> ValueOperations<String, T> setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit) {
        if(map != null) {
            map.put(key, value);
            mapTsp.put(key, new Date().getTime());
            mapTimeout.put(key, timeout);
            mapTimeUnit.put(key, timeUnit);
            return null;
        }
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        operation.set(key, value, timeout, timeUnit);
        return operation;
    }

    public String checkTsp(String key) {
        if(!map.containsKey(key)){
            return null;
        }
        if(mapTimeout.containsKey(key)) {
            if(TimeUnit.MINUTES.equals(mapTimeUnit.get(key))) {
                if(Math.abs(mapTsp.get(key) - new Date().getTime()) > mapTimeout.get(key)*60*1000) {
                    map.remove(key);
                    mapTimeout.remove(key);
                    mapTimeUnit.remove(key);
                    mapTsp.remove(key);
                    log.info("redis timeout:{}", key);
                    return "timeout";
                }
            } else if (TimeUnit.SECONDS.equals(mapTimeUnit.get(key))) {
                if(Math.abs(mapTsp.get(key) - new Date().getTime()) > mapTimeout.get(key)*1000) {
                    map.remove(key);
                    mapTimeout.remove(key);
                    mapTimeUnit.remove(key);
                    mapTsp.remove(key);
                    log.info("redis timeout:{}", key);
                    return "timeout";
                }
            }
        }
        return "ok";
    }
    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public <T> T getCacheObject(String key) {
        if(map != null) {
            checkTsp(key);
            return (T) map.get(key);
        }
        ValueOperations<String, T> operation = redisTemplate.opsForValue();
        return operation.get(key);
    }

    /**
     * 删除单个对象
     *
     * @param key
     */
    public void deleteObject(String key) {
        if(map != null) {
            map.remove(key);
            return;
        }
        redisTemplate.delete(key);
    }

    /**
     * 删除集合对象
     *
     * @param collection
     */
    public void deleteObject(Collection collection) {
        if(map != null) {
            for(Object o:collection.toArray()) {
                String key = (String) o;
                map.remove(key);
            }
            return;
        }
        redisTemplate.delete(collection);
    }

    /**
     * 缓存List数据
     *
     * @param key      缓存的键值
     * @param dataList 待缓存的List数据
     * @return 缓存的对象
     */
    public <T> ListOperations<String, T> setCacheList(String key, List<T> dataList) {
        if(map != null) {
            map.put(key, dataList);
            mapTsp.put(key, new Date().getTime());
            return null;
        }
        ListOperations listOperation = redisTemplate.opsForList();
        if (null != dataList) {
            int size = dataList.size();
            for (int i = 0; i < size; i++) {
                listOperation.leftPush(key, dataList.get(i));
            }
        }
        return listOperation;
    }

    /**
     * 获得缓存的list对象
     *
     * @param key 缓存的键值
     * @return 缓存键值对应的数据
     */
    public <T> List<T> getCacheList(String key) {
        if(map != null) {
            checkTsp(key);
            return (List<T>) map.get(key);
        }
        List<T> dataList = new ArrayList<T>();
        ListOperations<String, T> listOperation = redisTemplate.opsForList();
        Long size = listOperation.size(key);

        for (int i = 0; i < size; i++) {
            dataList.add(listOperation.index(key, i));
        }
        return dataList;
    }

    /**
     * 缓存Set
     *
     * @param key     缓存键值
     * @param dataSet 缓存的数据
     * @return 缓存数据的对象
     */
    public <T> BoundSetOperations<String, T> setCacheSet(String key, Set<T> dataSet) {
        if(map != null) {
            map.put(key, dataSet);
            mapTsp.put(key, new Date().getTime());
            return null;
        }
        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
        Iterator<T> it = dataSet.iterator();
        while (it.hasNext()) {
            setOperation.add(it.next());
        }
        return setOperation;
    }

    /**
     * 获得缓存的set
     *
     * @param key
     * @return
     */
    public <T> Set<T> getCacheSet(String key) {
        if(map != null) {
            checkTsp(key);
            return (Set<T>) map.get(key);
        }
        Set<T> dataSet = new HashSet<T>();
        BoundSetOperations<String, T> operation = redisTemplate.boundSetOps(key);
        dataSet = operation.members();
        return dataSet;
    }

    /**
     * 缓存Map
     *
     * @param key
     * @param dataMap
     * @return
     */
    public <T> HashOperations<String, String, T> setCacheMap(String key, Map<String, T> dataMap) {
        if(map != null) {
            map.put(key, dataMap);
            mapTsp.put(key, new Date().getTime());
            return null;
        }
        HashOperations hashOperations = redisTemplate.opsForHash();
        if (null != dataMap) {
            for (Map.Entry<String, T> entry : dataMap.entrySet()) {
                hashOperations.put(key, entry.getKey(), entry.getValue());
            }
        }
        return hashOperations;
    }

    /**
     * 获得缓存的Map
     *
     * @param key
     * @return
     */
    public <T> Map<String, T> getCacheMap(String key) {
        if(map != null) {
            checkTsp(key);
            return (Map<String, T>) map.get(key);
        }
        Map<String, T> map = redisTemplate.opsForHash().entries(key);
        return map;
    }

    /**
     * 获得缓存的基本对象列表
     *
     * @param pattern 字符串前缀
     * @return 对象列表
     */
    public Collection<String> keys(String pattern) {
        if(map != null) {
            return map.keySet();
        }
        return redisTemplate.keys(pattern);
    }

    /**
     * 更新过期时间
     *
     * @param key      缓存的键值
     * @param timeout  时间
     * @param timeUnit 时间颗粒度
     * @return 是否成功
     */
    public boolean expire(String key, Integer timeout, TimeUnit timeUnit) {
        if(map != null) {
            if(map.containsKey(key)) {
                mapTsp.put(key, new Date().getTime());
                mapTimeout.put(key, timeout);
                mapTimeUnit.put(key, timeUnit);
            }
            return true;
        }
        return redisTemplate.expire(key, timeout, timeUnit);
    }


}